package cn.buk.tms.eotms.service;

import cn.buk.common.flight.dto.FlightInfoDto;
import cn.buk.jedis.RedisDao;
import cn.buk.tms.common.constant.TmsConstant;
import cn.buk.tms.common.dto.CustomerDiscountInfoDto;
import cn.buk.tms.common.dto.MarkupConfigDto;
import cn.buk.tms.eotms.dao.BasicDataDao;
import cn.buk.tms.eotms.dao.CustomerDao;
import cn.buk.tms.eotms.dao.EnterpriseDao;
import cn.buk.tms.eotms.dao.UserDao;
import cn.buk.tms.eotms.dto.RoleInfo;
import cn.buk.tms.eotms.entity.*;
import cn.buk.tms.exception.BaseException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * @author yfdai
 */
public abstract class BaseAbstractService {

  private static final Logger logger = LogManager.getLogger(BaseAbstractService.class);

  @Autowired
  protected CustomerDao customerDao;

  @Autowired
  protected UserDao userDao;

  @Autowired
  protected BasicDataDao basicDataDao;

  @Autowired
  protected EnterpriseDao enterpriseDao;


  @Autowired
  protected RedisDao redisDao;

  /**
   * 获取当前用户所属上级企业的企业ID
   * @param userId
   * @return
   */
  protected int getOwnerIdByUserId(final int userId) {
    User user = userDao.getUserById(userId);

    if (user == null || user.getParentEnterprise() <= 0) {
      throw new RuntimeException("User is not existed.");
    }

    return user.getParentEnterprise();
  }

  protected int getEnterpriseIdByUserId(final int userId) {
    User user = userDao.getUserById(userId);

    if (user == null || user.getEnterpriseId() <= 0) {
      throw new RuntimeException("User is not existed.");
    }

    return user.getEnterpriseId();
  }

  protected Integer getPassengerIdByUserId(final int userId) {
    User user = userDao.getUserById(userId);

    if (user == null || user.getEnterpriseId() <= 0) {
      throw new RuntimeException("User is not existed.");
    }

    return user.getPassengerId();
  }

  /**
   * 获取当前用户所在企业对应的客户ID
   * @param userId
   * @return
   */
  protected int getCustomerIdByUserId(final int userId) {
    return getCustomerByUserId(userId).getId();
  }

  /**
   * 根据当前用户的id, 查找其所对应的企业客户资料
   * @param userId 当前用户id
   * @return 对应的企业客户资料
   */
  protected Customer getCustomerByUserId(final int userId) {
    User user = userDao.getUserById(userId);

    if (user == null || user.getParentEnterprise() <= 0) {
      throw new RuntimeException("User is not existed.");
    }

    final int ownerId = user.getParentEnterprise();
    final int customerEnterpriseId = user.getEnterpriseId();

    Customer customer = customerDao.getCustomerByCustomerEnterpriseId(ownerId, customerEnterpriseId);
    if (customer == null) {
      logger.error("{}, {}.", ownerId, customerEnterpriseId);
      throw new RuntimeException("User's customer is not existed.");
    }

    return customer;
  }

  /**
   * 查找用户所在部门的id
   * @param userId
   * @return
   */
  protected int getCustomerDeptIdByUserId(final int userId) {
    User user = userDao.getUserById(userId);
    if (user == null || user.getPassengerId() == 0) {
      return 0;
    }

    Passenger passenger = enterpriseDao.getPassengerById(user.getPassengerId());
    if (passenger.getDepartment() == null) {
      return 0;
    } else {
      return passenger.getDepartment().getId();
    }
  }

  protected String getUsernameByUserId(final int userId) {
    User user = userDao.getUserById(userId);

    if (user == null || user.getParentEnterprise() <= 0) {
      throw new RuntimeException("User is not existed.");
    }

    return user.getUsername();
  }

  protected void validateFlightInfo(FlightInfoDto info) throws BaseException {
    validateFlightInfo(info, false);
  }

  protected void validateFlightInfo(FlightInfoDto info, boolean ignoreSubclass) throws BaseException {
    if (info.getFlightNo() == null || info.getFlightNo().length() < 4 || info.getFlightNo().length() > 8) {
      throw new BaseException(20001, "航班号不能为空或格式不正确");

    }
    if (!ignoreSubclass) {
      if (info.getSubclass() == null || info.getSubclass().length() < 1 || info.getSubclass().length() > 2) {
        throw new BaseException(20002, "舱位不能为空或格式不正确");
      }
    }
    if (info.getDport() == null || info.getDport().length() != 3) {
      throw new BaseException(20003, "出发或到达机场不能为空或格式不正确");
    }
    if (info.getAport() == null || info.getAport().length() != 3) {
      throw new BaseException(20003, "出发或到达机场不能为空或格式不正确");
    }

    if (info.getDdate() == null) {
      throw new BaseException(20004, "出发日期不能为空");
    }

  }

  protected void processOrderAirportName(FlightOrder flightOrder) {
    //检查机场名是否有
    for (FlightOrderFlight flt : flightOrder.getFlights()) {
      processFlightAirportName(flt.getFlight());
    }
  }

  private void processFlightAirportName(FlightInfo flt) {
    if (flt.getDepartureAirportName() == null) {
      String airportName = getAirportName(flt.getDepartureAirport());
      flt.setDepartureAirportName(airportName);
    }

    if (flt.getArrivalAirportName() == null) {
      String airportName = getAirportName(flt.getArrivalAirport());
      flt.setArrivalAirportName(airportName);
    }

  }


  /**
   * 获取租车的优惠金额
   * @param enterpriseId
   * @param ownerId
   * @return
   */
  protected int doGetCarDiscount(final int enterpriseId, final int ownerId) {
    CustomerDiscountInfoDto dto = getCustomerDiscountInfo(enterpriseId, ownerId);
    return dto == null ? 0 : dto.getCarDiscount();
  }

  private CustomerDiscountInfoDto getCustomerDiscountInfo(final int enterpriseId, final int ownerId) {
    final String discountKey = String.format(TmsConstant.CUSTOMER_OT_DISCOUNT, ownerId, enterpriseId);
    byte[] bytes = redisDao.get(discountKey);
    if (bytes != null && bytes.length > 0) {
      return JSON.parseObject(new String(bytes, UTF_8), CustomerDiscountInfoDto.class);
    } else {
      return null;
    }
  }

  /**
   * 获取租车加价金额
   * @return
   */
  protected int doGetCarMarkup(final int ownerId) {
    //获取加价信息
    MarkupConfigDto dto = getMarkupInfo(ownerId);
    return dto == null ? 0: dto.getCarMarkup();
  }

  private MarkupConfigDto getMarkupInfo(final int ownerId) {
    final String markupKey = String.format(TmsConstant.GLOBAL_MARKUP, ownerId);
    byte[] bytes = redisDao.get(markupKey);
    if (bytes != null && bytes.length > 0) {
      return JSON.parseObject(new String(bytes, UTF_8), MarkupConfigDto.class);
    } else {
      return null;
    }
  }

  /**
   * 获取登机牌加价
   * @param ownerId
   * @return
   */
  protected int doGetBoardingCardMarkup(final int ownerId) {
    //获取加价信息
    MarkupConfigDto dto = getMarkupInfo(ownerId);
    return dto == null ? 0: dto.getBoardingCardMarkup();
  }

  /**
   * 获取登机牌指定用户的优惠金额
   * @param enterpriseId
   * @param ownerId
   * @return
   */
  protected int doGetBoardingCardDiscount(final int enterpriseId, final int ownerId) {
    CustomerDiscountInfoDto dto = getCustomerDiscountInfo(enterpriseId, ownerId);
    return dto == null ? 0 : dto.getBoardingCardDiscount();
  }

  /**
   * 获取用户的角色
   * @param userId
   * @return
   */
  protected Set<String> getRolesByUserId(final int userId) {
    int enterpriseId = getEnterpriseIdByUserId(userId);
    return getRolesByUserId(enterpriseId, userId);
  }

  /**
   * 获取用户在EOTMS中所拥有的所有角色
   * @param enterpriseId
   * @param userId
   * @return
   */
  protected Set<String> getRolesByUserId(final int enterpriseId, final int userId) {
    Set<String> roles = new HashSet<>();
    roles.add(RoleInfo.ROLE_USER);

    if (enterpriseId == userId) {
      roles.add(RoleInfo.ROLE_ADMIN);
    }

    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    List<CustomerTravelApprover> approvers = enterpriseDao.searchCustomerApprovers(ownerId, customerId);
    for(CustomerTravelApprover approver: approvers) {
      if (approver.getRoleType() == RoleInfo.ROLE_MANAGER_ID) {
        roles.add(RoleInfo.ROLE_MANAGER);
      } else if (approver.getRoleType() == RoleInfo.ROLE_APPROVER_ID){
        roles.add(RoleInfo.ROLE_APPROVER);
      }
    }

    return roles;
  }

  protected Workbook create(InputStream inp) throws IOException {
    if (!inp.markSupported()) {
      inp = new PushbackInputStream(inp, 8);
    }

    return WorkbookFactory.create(inp);
//    if (POIFSFileSystem.hasPOIFSHeader(inp)) {
//      return new HSSFWorkbook(inp);
//    }
//    if (POIXMLDocument.hasOOXMLHeader(inp)) {
//      return new XSSFWorkbook(OPCPackage.open(inp));
//    }
//    logger.error("Your excel version can not be parsed by poi.");
//    throw new IllegalArgumentException("Your excel version can not be parsed by poi.");
  }

  protected String getStringCellValue(Cell cell) {
    if (cell == null) {
      return null;
    }

    if (cell.getCellType() == CellType.STRING) {
      return cell.getStringCellValue().trim();
    } else if (cell.getCellType() == CellType.NUMERIC) {
      DataFormatter dataFormatter = new DataFormatter();
      dataFormatter.addFormat("###########", null);
      return dataFormatter.formatCellValue(cell);
    } else {
      logger.info("cell type is not expected.");
      return null;
    }
  }

  /**
   * 获取机场名字
   *
   * @param code
   * @return 城市名+机场名
   */
  protected String getAirportName(final String code) {
    String dportName = null;
    final String key = String.format(TmsConstant.AIRPORT_INFO, code.trim());
    try {
      String jsonStr = new String(redisDao.get(key), UTF_8);

      JSONObject obj = JSON.parseObject(jsonStr);
      String airportName = obj.getString("nameCN");
      String cityName = obj.getString("cityName");
      String cityCode = obj.getString("cityCode");

      if (cityCode == null) {
        dportName = cityName;
      } else if (cityCode.equalsIgnoreCase("SHA") || "BJS".equalsIgnoreCase(cityCode)) {
        dportName = cityName + airportName;
      } else {
        dportName = cityName;
      }


    } catch (Exception ignored) {
    }


    return dportName;
  }


}
